#include "Decoder.h"

Decoder::Decoder(AVFormatContext *ic, MediaType type, int stream, PacketQueue *pkt_queue)
{
    m_MediaType = type;
    m_Ic = ic;
    m_Stream = stream;
    m_PktPending = false;
    m_PacketQueue = pkt_queue;
}

Decoder::~Decoder()
{
    close();
}

int Decoder::open()
{
    int ret  = 0;
    if (m_Stream < 0 || m_Stream >= m_Ic->nb_streams) {
        LOGE("m_Stream error, m_Stream:%d, nb_streams:%d", m_Stream, m_Ic->nb_streams);
        return -1;
    }
    m_Avctx = avcodec_alloc_context3(NULL);
    if (!m_Avctx){
        return AVERROR(ENOMEM);
    }

    ret = avcodec_parameters_to_context(m_Avctx, m_Ic->streams[m_Stream]->codecpar);
    if (ret < 0){
        goto fail;
    }

    av_codec_set_pkt_timebase(m_Avctx, m_Ic->streams[m_Stream]->time_base);
    m_Codec = avcodec_find_decoder(m_Avctx->codec_id);

    if (!m_Codec) {
		LOGE("No codec could be found with id %d", m_Avctx->codec_id);
        ret = AVERROR(EINVAL);
        goto fail;
    }

    if ((ret = avcodec_open2(m_Avctx, m_Codec, NULL)) < 0) {
        LOGE("open decoder error!\n");
        goto fail;
    }
    return 0;

fail:
    avcodec_free_context(&m_Avctx);
    return ret;
}

void Decoder::close()
{
    LOGD("Decoder close");
    if (m_Avctx) {
        avcodec_free_context(&m_Avctx);
        m_Avctx = NULL;
    }
}

int Decoder::decode(AVFrame *frame)
{
#if 0
    int ret = AVERROR(EAGAIN);
    for (;;) {

    	ret = avcodec_send_packet(m_Avctx, pkt);
        if (ret == AVERROR(EAGAIN)) {
            LOGE("Receive_frame and send_packet both returned EAGAIN, which is an API violation.");
            m_PktPending = true;
            //av_packet_move_ref(&d->pkt, &pkt);
            return AVERROR(EAGAIN);
        }
        av_packet_unref(pkt);
receive_frame:
        ret = avcodec_receive_frame(m_Avctx, frame);
        if (ret == AVERROR_EOF) {
            avcodec_flush_buffers(m_Avctx);
            return 0;
        }
        if (ret >= 0)
            return 1;

        if(ret != AVERROR(EAGAIN))
            goto receive_frame;

        return AVERROR(EAGAIN);
    }
#endif
    int ret = AVERROR(EAGAIN);
    AVPacket pending_pkt;
    AVPacket read_pkt;
    int serial;
    for (;;) {
        do {
            ret = avcodec_receive_frame(m_Avctx, frame);

            if (ret == AVERROR_EOF) {
                avcodec_flush_buffers(m_Avctx);
                return 0;
            }
            if (ret >= 0)
                return 1;
        } while (ret != AVERROR(EAGAIN));

        if (m_PktPending) {
            av_packet_move_ref(&read_pkt, &pending_pkt);
            m_PktPending = false;
        } else {
            ret = m_PacketQueue->get(read_pkt, serial);
            if(ret < 0) {
                return -1;
            }
        }

        if (avcodec_send_packet(m_Avctx, &read_pkt) == AVERROR(EAGAIN)) {
            LOGE("Receive_frame and send_packet both returned EAGAIN, which is an API violation.");
            m_PktPending = true;
            av_packet_move_ref(&pending_pkt, &read_pkt);
        }
        av_packet_unref(&read_pkt);
    }
}

// VideoDecoder::VideoDecoder(AVFormatContext *ic, int stream)
// : Decoder(ic, Decoder::MEDIA_TYPE_VIDEO, stream)
// {

// }

// VideoDecoder::~VideoDecoder()
// {

// }

// int VideoDecoder::decode(AVPacket &pkt, AVFrame &frame)
// {

// }